﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO.Ports;
using System.Threading;
using System.IO;
using System.Globalization;
using debugger;
using SDcard;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;

namespace WindowsFormsApplication1
{

	public sealed partial class Form1 : Base
	{
        public static uint CACHE_CTL = 0x42000000;

		public Form1()
		{
			InitializeComponent();

			this.FormClosed += new FormClosedEventHandler(Form1_FormClosed);
            this.comboBox1.Click += comboBox1_Click;
		}

		void Form1_FormClosed(object sender, FormClosedEventArgs e)
		{
			if (port != null && port.IsOpen)
			{
				port.Close();
			}
		}
		string portName;

		private void Form1_Load(object sender, EventArgs e)
		{
			foreach (var item in this.Controls)
			{
				(item as Control).Enabled = false;
			}
			this.comboBox1.Enabled = true;
			this.button1.Enabled = true;
			this.button10.Enabled = true;
			this.textBox3.Enabled = true;
			this.button15.Enabled = true;
			this.button13.Enabled = true;
			loadSym();
		}
		private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
		{
			portName = (string)this.comboBox1.SelectedItem;
		}

		void comboBox1_Click(object sender, System.EventArgs e)
		{
			String[] list = SerialPort.GetPortNames();
			this.comboBox1.Items.Clear();
            this.comboBox1.Items.Add("dummy");
			foreach (String s in list)
			{
				this.comboBox1.Items.Add(s);
			}
			this.comboBox2.SelectedIndex = 0;
		}


		private void button1_Click(object sender, EventArgs e)
		{
            if ("dummy" != portName)
            {
                connect(portName);
            }
			foreach (var item in this.Controls)
			{
				(item as Control).Enabled = true;
			}
		}

		List<CodeSym> syms;

		private void button2_Click(object sender, EventArgs e)
		{
			if (port != null && port.IsOpen)
			{
				port.Close();
				port = null;
			}
		}
        

		private void button4_Click(object sender, EventArgs e)
		{
			try
			{
				getstatus();
			}
			catch (Exception ex)
			{
				MessageBox.Show(ex.Message);
			}
		}
        public int getDataNew(int cmd, StringBuilder sb)
        {
            portWriteNew((byte)(cmd), (byte)0x00);
            int val = 0;
            val = (int)readFromPort();
            if (sb != null) sb.Append(Util.getHex8(val));
            return val;
        }

        public void getCacheDebugData(int id, StringBuilder sb, out int addr, out int life, out string invalid, out string dirty, bool isIns = false)
        {
            portWriteNew((byte)(0x67), (byte)id);
            int val;
            if (isIns)
            {
                val = getDataNew(0x6C, null);
            }
            else
            {
                val = getDataNew(0x68, null);
            }
            //                     16                             1                                15
            //cache_debug_data <= {cache_life[cache_debug_index], cacheInvalid[cache_debug_index], cacheAddrHigh[cache_debug_index]};

            if ((val & 0x80000000) != 0)
            {
                dirty = " D";
            }
            else
            {
                dirty = "  ";
            }
            if ((val & 0x8000) != 0)
            {
                invalid = "  ";
            }
            else
            {
                invalid = " V";
            }
            addr = (val & 0x7fff) << 10;
            if (sb != null)
            {
                sb.Append(dirty + invalid + Util.getHex8((uint)addr));
            }

            life = (val >> 16) & 0x7fff;
            if (sb != null)
            {
                sb.Append(String.Format(",{0: 00}", life));
            }

        }


		public int getAccessTime()
		{
			return getDataNew(0x4, null);
		}
        public uint getreg(byte reg, StringBuilder sb)
        {
            uint val = getmem(reg, null, false, true);
            sb.Append(Util.getHex8(val));
            return val;
        }

		public void getstatus()
		{
			uint temp;
			clearBuff();

			int baseaddr = 0;


			portWriteNew((byte)(0x08), (byte)(123));
			temp = readFromPort();
			if (temp != 123)
			{
				throw new Exception("checkerror");
			}

			StringBuilder sb = new StringBuilder();

            int pc;

            try
            {
                pc = Convert.ToInt32(textBox6.Text, 16);
            }
            catch
            {
                sb.Append("pc:");
                portWriteNew(0x43, 0);
                pc = (int)readFromPort();
                sb.Append(Util.getHex8(pc));
            }

			sb.Append("  private_offset:");
            portWriteNew(0x44, 0);
            sb.Append(Util.getHex8(readFromPort()));

			sb.Append("  pcResult:");
            portWriteNew(0x45, 0);
            sb.Append(Util.getHex8(readFromPort()));

			//sb.Append("  last RtypeCmd:");
			//portWrite((byte)(0x18), (byte)0x00); temp = readFromPort(1); sb.Append(Util.getHex2(temp[0]));

            //4        3         2                  1          0
            //halt_cpu,halt_uart,avm_m0_waitrequest,irq_enable,irq_req
            portWriteNew((byte)(0x14), (byte)0x00);
            temp = readFromPort();

            uint halt_cpu = (temp>>4) & 1;
			sb.Append("  halt_cpu:");
            sb.Append(halt_cpu);

            uint halt_uart = (temp >> 3) & 1;
			sb.Append("  halt_uart:");
            sb.Append(halt_uart);

			sb.Append("  waitRequest:");
            sb.Append((temp >> 2) & 1);
            
			sb.Append("  waitRequestIns:");
            sb.Append((temp >> 5) & 1);

            sb.Append("  irq_enable:");
            sb.Append((temp >> 1) & 1);

            sb.Append("  irq_req:");
            sb.Append((temp >> 0) & 1);

			sb.Append("  irq_addr:");
            portWriteNew((byte)(0x40), (byte)0x00);
            sb.Append( Util.getHex8(readFromPort()));

            sb.Append("  cpu_address:");
            portWriteNew((byte)(0x41), (byte)0x00);
            sb.Append( Util.getHex8(readFromPort()));
            

  			sb.Append("  curr_data:");
            portWriteNew((byte)( 0x46), (byte)0x00);
            sb.Append( Util.getHex8(readFromPort()));

			sb.Append("  debugin:");
            portWriteNew((byte)(0x64), (byte)0x00);
            sb.Append(Util.getBin8(readFromPort()));
			sb.Append("  debugin32:");
            portWriteNew((byte)(0x60), (byte)0x00);
            sb.Append(Util.getHex8(readFromPort()));

			sb.AppendLine();

			sb.Append("  access time:");
			sb.Append(getAccessTime());
			sb.AppendLine();

            sb.Append("  pc_record_Index:");
            portWriteNew((byte)(0x10), (byte)0x00);
            uint pc_index = readFromPort();
            sb.Append(pc_index);
            sb.AppendLine();
            for (int i = 0; i < 4; i++)
            {
                sb.Append("  pc_record:" + (byte)(pc_index + i - 4) + ",");
                portWriteNew((byte)(0x09), (byte)(pc_index + i - 4));
                sb.Append(Util.getHex8(readFromPort()));
                sb.AppendLine();
            }

			sb.Append("cache:");
            portWriteNew((byte)(0x6A), (byte)0x00);
            sb.Append(Util.getHex8(readFromPort()));
            sb.Append("  flush count:");
            portWriteNew((byte)(0x6B), (byte)0x00);
            sb.Append(Util.getHex8(readFromPort()));
            sb.AppendLine();

            portWriteNew((byte)(0x6D), (byte)0x00);
             temp = readFromPort();
             int cache_count = (int)(temp & 0xFF);
             int group_count = (int)((temp>>8) & 0xFF);

             int cache_count_ins = (int)((temp >> 16) & 0xFF);
             int group_count_ins = (int)((temp >> 24) & 0xFF);
        

            for (int j = 0; j < group_count; j++)
            {
                sb.Append("Group:" + j+" ");
                for (int i = 0; i < cache_count; i++)
                {
                    //sb.Append(String.Format("{0:00}", i) + ":[");
                    sb.Append(" [");
                    int life;
                    int addr;
                    string invalid;
                    string dirty;
                    getCacheDebugData(i * group_count+j, sb, out life, out addr, out invalid, out dirty);
                    sb.Append("] ");
                    //if ((i & 7) == 7) sb.AppendLine();
                }
                sb.AppendLine();
            }

            for (int j = 0; j < group_count_ins; j++)
            {
                sb.Append("GroupIns:" + j+" ");
                for (int i = 0; i < cache_count_ins; i++)
                {
                    //sb.Append(String.Format("{0:00}", i) + ":[");
                    sb.Append(" [");
                    int life;
                    int addr;
                    string invalid;
                    string dirty;
                    getCacheDebugData(i * group_count+j, sb, out life, out addr, out invalid, out dirty, true);
                    sb.Append("] ");
                    //if ((i & 7) == 7) sb.AppendLine();
                }
                sb.AppendLine();
            }

			//sb.Append("  numer:"); getreg(0x40, 0, sb);
			//sb.Append("  denom:"); getreg(0x41, 0, sb);
			//sb.Append("  quotient:"); getreg(0x42, 0, sb);
			//sb.Append("  remain:"); getreg(0x45, 0, sb);


			sb.AppendLine();

			if (true && (halt_cpu != 0 || halt_uart != 0))
			{

				sb.Append("r0:");
				getreg(0x00, sb);
				sb.Append(" r1:");
				getreg(0x01, sb);

				sb.Append("   r2:");
				getreg(0x02, sb);
				sb.Append(" r3:");
				getreg(0x03, sb);
				sb.AppendLine();

				for (int i = 4; i < 8; i++)
				{
					sb.Append(" r" + i + ":");
					getreg((byte)i, sb);
				}
				sb.AppendLine();

				for (int i = 8; i < 16; i++)
				{
					sb.Append(" r" + i + ":");
					getreg((byte)i, sb);
				}
				sb.AppendLine();

				for (int i = 16; i < 24; i++)
				{
					sb.Append(" r" + i + ":");
					getreg((byte)i, sb);
				}
				sb.AppendLine();

				sb.Append("sp:");
				int sp = (int)getreg(27, sb);

				sb.Append("    fp:");
				getreg(28, sb);
				sb.AppendLine();

				sb.Append(" re:");
				getreg(29, sb);

				sb.Append(" ra:");
				getreg(31, sb);
				sb.AppendLine();


				sb.AppendLine("stack: ");
				baseaddr = sp;
				for (int i = -Convert.ToInt32(this.comboBox2.Text) * 4; i < Convert.ToInt32(this.comboBox2.Text) * 4; i += 4)
				{
					sb.Append((i == 0 ? "*" : " ") + Util.getHex8((uint)(i + baseaddr)) + ":"); getmem((uint)(baseaddr + i), sb); sb.AppendLine();
				}

				baseaddr = 0;
				sb.AppendLine("code: ");
				for (int i = -Convert.ToInt32(this.comboBox2.Text) * 4; i < Convert.ToInt32(this.comboBox2.Text) * 4; i += 4)
				{
					StringBuilder sb2 = new StringBuilder();
					uint code = getmem((uint)(pc + i), sb2, true);
					int target = pc + i;
					string foundsym = Config.getSym(target, syms);
					string scode = Config.dasm(syms, cfgs, (uint)code, pc + i, baseaddr);
					if (i == 0)
					{
						sb.AppendLine("----------------------------------------------------------------------------------");
					}
					sb.AppendLine((i == 0 ? "*" : " ") + Util.getHex8((uint)(pc + i)) + ":" + scode);
					if (i == 0)
					{
						sb.AppendLine("----------------------------------------------------------------------------------");
					}
				}

				sb.AppendLine("mem: ");
				baseaddr = Convert.ToInt32(textBox1.Text, 16);
				for (int i = 0; i < Convert.ToInt32(this.comboBox2.Text) * 4 * 2; i += 4)
				{
					sb.Append("" + Util.getHex8((uint)(baseaddr + i)) + ":"); getmem((uint)(baseaddr + i), sb); sb.AppendLine();
				}
			}

			this.textBox4.Text = sb.ToString();
			Application.DoEvents();
		}

		private void textBox4_TextChanged(object sender, EventArgs e)
		{

		}

		//public int getData(int baseCmd, StringBuilder sb)
		//{
		//	byte[] temp;
		//	int val = 0;
		//	portWrite((byte)(baseCmd + 0x3), (byte)0x00); temp = readFromPort(1); val |= temp[0] << 24; if (sb != null) sb.Append(Util.getHex2(temp[0]));
		//	portWrite((byte)(baseCmd + 0x2), (byte)0x00); temp = readFromPort(1); val |= temp[0] << 16; if (sb != null) sb.Append(Util.getHex2(temp[0]));
		//	portWrite((byte)(baseCmd + 0x1), (byte)0x00); temp = readFromPort(1); val |= temp[0] << 8; if (sb != null) sb.Append(Util.getHex2(temp[0]));
		//	portWrite((byte)(baseCmd + 0x0), (byte)0x00); temp = readFromPort(1); val |= temp[0] << 0; if (sb != null) sb.Append(Util.getHex2(temp[0]));
		//	return val;
		//}

        uint? buff_addr;

        uint? buff_data;

        public uint getmem(uint addr, StringBuilder sb, bool isIns = false, bool isReg = false)
		{
			byte a0 = (byte)((addr >> 0) & 0xFF);
			byte a1 = (byte)((addr >> 8) & 0xFF);
			byte a2 = (byte)((addr >> 16) & 0xFF);
			byte a3 = (byte)((addr >> 24) & 0xFF);

            if (buff_addr == null)
            {
                portWriteNew((byte)(0x20), a0);
                portWriteNew((byte)(0x21), a1);
                portWriteNew((byte)(0x22), a2);
                portWriteNew((byte)(0x23), a3);
            }
            else
            {
                byte buff_a0 = (byte)((buff_addr >> 0) & 0xFF);
                byte buff_a1 = (byte)((buff_addr >> 8) & 0xFF);
                byte buff_a2 = (byte)((buff_addr >> 16) & 0xFF);
                byte buff_a3 = (byte)((buff_addr >> 24) & 0xFF);
                if (buff_a0 != a0) { portWriteNew((byte)(0x20), a0); }
                if (buff_a1 != a1) { portWriteNew((byte)(0x21), a1); }
                if (buff_a2 != a2) { portWriteNew((byte)(0x22), a2); }
                if (buff_a3 != a3) { portWriteNew((byte)(0x23), a3); }
            }
            buff_addr = addr;
            if (isIns)
            {
                portWriteNew((byte)(0x32), 0);
            }
            else if (isReg)
            {
                portWriteNew((byte)(0x47), 0);
            }
            else
            {
                portWriteNew((byte)(0x30), 0);
            }
            uint val = readFromPort();

			if (sb != null)
			{
                sb.Append(Util.getHex8(val));
			}
            buff_addr += 4;
            return val;
		}

		public bool setmem(uint addr, uint data, bool noerr = false, bool no31 = false, bool isReg = false)
		{
			byte a0 = (byte)((addr >> 0) & 0xFF);
			byte a1 = (byte)((addr >> 8) & 0xFF);
			byte a2 = (byte)((addr >> 16) & 0xFF);
			byte a3 = (byte)((addr >> 24) & 0xFF);

			byte d0 = (byte)((data >> 0) & 0xFF);
			byte d1 = (byte)((data >> 8) & 0xFF);
			byte d2 = (byte)((data >> 16) & 0xFF);
			byte d3 = (byte)((data >> 24) & 0xFF);

            if (buff_addr == null)
            {
                portWriteNew((byte)(0x20), a0);
                portWriteNew((byte)(0x21), a1);
                portWriteNew((byte)(0x22), a2);
                portWriteNew((byte)(0x23), a3);
            }
            else
            {
                byte buff_a0 = (byte)((buff_addr >> 0) & 0xFF);
                byte buff_a1 = (byte)((buff_addr >> 8) & 0xFF);
                byte buff_a2 = (byte)((buff_addr >> 16) & 0xFF);
                byte buff_a3 = (byte)((buff_addr >> 24) & 0xFF);
                if (buff_a0 != a0) { portWriteNew((byte)(0x20), a0); }
                if (buff_a1 != a1) { portWriteNew((byte)(0x21), a1); }
                if (buff_a2 != a2) { portWriteNew((byte)(0x22), a2); }
                if (buff_a3 != a3) { portWriteNew((byte)(0x23), a3); }
            }
            buff_addr = addr;

            if (buff_data == null)
            {
                portWriteNew((byte)(0x24), d0);
                portWriteNew((byte)(0x25), d1);
                portWriteNew((byte)(0x26), d2);
                portWriteNew((byte)(0x27), d3);
            }
            else
            {
                byte buff_d0 = (byte)((buff_data >> 0) & 0xFF);
                byte buff_d1 = (byte)((buff_data >> 8) & 0xFF);
                byte buff_d2 = (byte)((buff_data >> 16) & 0xFF);
                byte buff_d3 = (byte)((buff_data >> 24) & 0xFF);
                if (buff_d0 != d0) { portWriteNew((byte)(0x24), d0); }
                if (buff_d1 != d1) { portWriteNew((byte)(0x25), d1); }
                if (buff_d2 != d2) { portWriteNew((byte)(0x26), d2); }
                if (buff_d3 != d3) { portWriteNew((byte)(0x27), d3); }
            }
            buff_data = data;

            if (!no31)
            {
                if (isReg)
                {
                    portWriteNew((byte)(0x48), 0);
                }
                else
                {
                    portWriteNew((byte)(0x31), 0);
                }
                uint temp = readFromPort();
                if (temp != 123)
                {
                    if (!noerr)
                    {
                        throw new Exception("err");
                    }
                    else
                    {
                        return false;
                    }
                }
                buff_addr += 4;
            }
			return true;
		}

		private void button2_Click_1(object sender, EventArgs e)
		{

			clearBuff();

			uint addr = Convert.ToUInt32(textBox1.Text, 16);

			//NoCache(addr, checkBox8.Checked);

			StringBuilder sb = new StringBuilder();

            getmem(addr, sb, checkBox2.Checked, checkBox9.Checked);

			textBox2.Text = sb.ToString();
			//getstatus();

            uint inc = Convert.ToUInt32(textBox5.Text, 16);
            addr += inc;
            textBox1.Text = Util.getHex8(addr);

		}

        private void button15_Click(object sender, EventArgs e)
        {
            uint addr = Convert.ToUInt32(textBox1.Text, 16);
            this.FlushCache(addr);
        }

		public void writeByteEnable(int byteEnable)
		{
			portWriteNew((byte)(0x28), (byte)byteEnable);
		}

		private void button6_Click(object sender, EventArgs e)
		{
			clearBuff();

			int byteEnable = 0;
			byteEnable |= this.checkBox4.Checked ? 8 : 0;
			byteEnable |= this.checkBox5.Checked ? 4 : 0;
			byteEnable |= this.checkBox6.Checked ? 2 : 0;
			byteEnable |= this.checkBox7.Checked ? 1 : 0;
			writeByteEnable(byteEnable);

			uint addr = Convert.ToUInt32(textBox1.Text, 16);
            uint val = Convert.ToUInt32(textBox2.Text, 16);
            setmem(addr, val, false, false, checkBox9.Checked);

            uint inc = Convert.ToUInt32(textBox5.Text, 16);
            addr += inc;
            textBox1.Text = Util.getHex8(addr);

			//getstatus();
		}


		private void checkBox1_CheckedChanged(object sender, EventArgs e)
		{
			if (checkBox1.Checked)
			{
				portWriteNew((byte)(0x01), 1);
			}
			else
			{
				portWriteNew((byte)(0x01), 0);
			}

		}

		private void button3_Click_1(object sender, EventArgs e)
		{
			portWriteNew((byte)(0x03), 0);
			getstatus();
		}

		public void clearBuff()
		{
			buff_addr = null;

			buff_data = null;

            portWriteNew((byte)(0x00), (byte)(0x00));
            int val = port.BytesToRead;
            if (val > 0) {
                byte[] buff = new byte[1000];
                port.Read(buff,0,val);
            }
		}
		private void button5_Click(object sender, EventArgs e)
		{
			clearBuff();
		}
		private void button12_Click(object sender, EventArgs e)
		{
			for (int i = 0; i < 256; i++)
			{
				getmem(0x00001000, null);
				getmem(0x00002000, null);
				getmem(0x00003000, null);
				getmem(0x00004000, null);
			}
		}

		private void button13_Click(object sender, EventArgs e)
		{
            String[] files = Directory.GetFiles(@"E:\fpgaproj\mine.new\", "*.bmp");

			foreach (var item in files)
			{
				Bitmap b = new Bitmap(item);

				FileStream fs = new FileStream(item.Replace(".bmp",".img"), FileMode.CreateNew, FileAccess.Write);
				for (int j = 0; j < b.Height; j++)
				{
                    for (int i = 0; i < b.Width; i++)
					{
						uint val = getpixel(b.GetPixel(i, j));
						fs.WriteByte((byte)val);
						fs.WriteByte((byte)(val >> 8));
					}
				}
				fs.Close();
			}
		}
		private uint getpixel(Color c)
		{
			uint val = 0;
			val += ((uint)(c.R) >> 3) << (5 + 6);
			val += ((uint)(c.G) >> 2) << (5);
			val += ((uint)(c.B) >> 3);
			return val;
		}

		private void setpixel(int x, int y)
		{
			if ((x & 1) == 0)
			{
				setmem((uint)(0x00200000 + x * 2 + y * 2048), 0x0000FFFF);
			}
			else
			{
				setmem((uint)(0x00200000 + x * 2 + y * 2048), (uint)(0x0000FFFF) << 16);
			}
		}
		private void clearpixel(int x, int y)
		{
			if ((x & 1) == 0)
			{
				setmem((uint)(0x00200000 + x * 2 + y * 2048), 0x00000000);
			}
			else
			{
				setmem((uint)(0x00200000 + x * 2 + y * 2048), 0x00000000);
			}
		}

		uint[] data;

		public int FlushCache(uint addr)
		{
            setmem(CACHE_CTL, 0x80000000 | (addr >> 10));
			getmem(addr, null);
            int time = this.getAccessTime();
            setmem(CACHE_CTL, 0);
            return time;
		}
		public uint getValue(byte[] arr, int pos)
		{
			uint val = 0;
			val |= arr[(pos << 2) + 0];
			val |= ((uint)arr[(pos << 2) + 1]) << 8;
			val |= ((uint)arr[(pos << 2) + 2]) << 16;
			val |= ((uint)arr[(pos << 2) + 3]) << 24;
			return val;
		}
        bool stop = false;
		private void button7_Click(object sender, EventArgs e)
		{
            /*
            debugport test 
            int ok = 0;
            int ng = 0;
            int ex = 0;
            Random r = new Random();
            byte[] buff = new byte[1024];
            r.NextBytes(buff);
            while (true)
            {
                for (int i = 0; i < 1024; i++)
                {
                    try
                    {
                        portWriteNew((byte)(0x08), buff[i]);
                        uint temp = readFromPort();
                        if (temp != buff[i])
                        {
                            ng++;
                        }
                        else
                        {
                            ok++;
                        }
                    }
                    catch (Exception exc) { 
                        ex++;
                    }
                }
                this.Text = "ok:" + ok + " ng" + ng + " ex:" + ex;
                Application.DoEvents();
                if (stop) {
                    break;
                }
            }
            return;*/


			Form2 form2 = new Form2();
			form2.mainForm = this;
			form2.Show();
		}

		List<Config> cfgs;

		private void loadSym()
		{
			cfgs = Config.loadConfig(@"assembler\config.txt");

			syms = new List<CodeSym>();
			FileStream fs = new FileStream("temp.sym", FileMode.Open, FileAccess.Read);
			StreamReader sw = new StreamReader(fs);
			string s = sw.ReadToEnd();
			sw.Close();
			fs.Close();
			foreach (var line in s.Split('\n'))
			{
				if (line != "")
				{
					CodeSym sym = new CodeSym();
					sym.pos = int.Parse(line.Split(',')[0]);
					sym.name = line.Split(',')[1];
					syms.Add(sym);
				}
			}
		}


		private void button8_Click(object sender, EventArgs e)
		{

		}

		private void button9_Click(object sender, EventArgs e)
		{
            clearBuff();

            portWriteNew((byte)(0x02), 0);

			Thread.Sleep(100);

            portWriteNew((byte)(0x02), 1);

		}

		private void button10_Click(object sender, EventArgs e)
		{
			/*
struct bpb_t {//biosParmBlock
  char bytesPerSector_0;
  char bytesPerSector_1;
  char sectorsPerCluster;
  char reservedSectorCount_0;
  char reservedSectorCount_1;
  char fatCount; 
  char rootDirEntryCount_0;
  char rootDirEntryCount_1;
  char totalSectors16_0;
  char totalSectors16_1;

  char mediaType;

  char sectorsPerFat16_0;
  char sectorsPerFat16_1;
  char sectorsPerTrtack_0;
  char sectorsPerTrtack_1;
  char headCount_0;
  char headCount_1;
  char hidddenSectors_0;
  char hidddenSectors_1;
  char hidddenSectors_2;
  char hidddenSectors_3;

  char totalSectors32_0;
  char totalSectors32_1;
  char totalSectors32_2;
  char totalSectors32_3;
  char sectorsPerFat32_0;
  char sectorsPerFat32_1;
  char sectorsPerFat32_2;
  char sectorsPerFat32_3;
  char fat32Flags_0;
  char fat32Flags_1;

  char fat32Version_0;
  char fat32Version_1;
  char fat32RootCluster_0;
  char fat32RootCluster_1;
  char fat32RootCluster_2;
  char fat32RootCluster_3;
  char fat32FSInfo_0;
  char fat32FSInfo_1;
  char fat32BackBootBlock_0;
  char fat32BackBootBlock_1;

  char fat32Reserved[12];
};41+12

struct fbs_t {//fat32BootSector
  char jmpToBootCode[3]; 3
  char oemName[8]; 8 
  bpb_t bpb; 41+12

  char driveNumber;
  char reserved1;
  char bootSignature;
  char volumeSerialNumber_0;
  char volumeSerialNumber_1;
  char volumeSerialNumber_2;
  char volumeSerialNumber_3;  7

  char volumeLabel[11]; 11 
  char fileSystemType[8]; 8
  char bootCode[420];
  char bootSectorSig0;
  char bootSectorSig1;
};
struct dir_t {//directoryEntry
  char name[11];
  char attributes;
  char reservedNT;
  char creationTimeTenths;
  char creationTime_0;
  char creationTime_1;

  char creationDate_0;
  char creationDate_1;
  char lastAccessDate_0;
  char lastAccessDate_1;
  char firstClusterHigh_0; 20
  char firstClusterHigh_1;
  char lastWriteTime_0;
  char lastWriteTime_1;
  char lastWriteDate_0;
  char lastWriteDate_1;
  char firstClusterLow_0; 26
  char firstClusterLow_1;
  char fileSize_0;
  char fileSize_1;
  char fileSize_2;
  char fileSize_3;
};

			 */
			SDUtils sd = new SDUtils(this.textBox3.Text + ":");
			byte[] fbs = sd.ReadSector(0);
			int volumeStartBlock = 0;
			int reservedSectorCount = fbs[3 + 8 + 3 + 0] | (fbs[3 + 8 + 3 + 1] << 8);
			int fatStartBlock = volumeStartBlock + reservedSectorCount;

			int fatCount = fbs[3 + 8 + 5];
			int blocksPerFat = fbs[3 + 8 + 11 + 0] | (fbs[3 + 8 + 11 + 1] << 8);
			int rootDirStart = fatStartBlock + fatCount * blocksPerFat;

			int rootDirEntryCount = fbs[3 + 8 + 6 + 0] | (fbs[3 + 8 + 6 + 1] << 8);

			int dataStartBlock = rootDirStart + (((rootDirEntryCount << 5) + 511) >> 9);


			byte[] root = sd.ReadSector(rootDirStart);
			string name = "BOOT    BIN";
			//string name = "TEST1   TXT";
			int index = -1;
			for (int i = 0; i < 512; i += 32)
			{
				int match = 1;
				for (int j = 0; j < 11; j++)
				{
					if (root[i + j] != (byte)name[j])
					{
						match = 0;
						break;
					}
				}
				if (match == 1)
				{
					index = i;
				}
			}

			int firstCluster;
			int fileSize;
			if (index >= 0)
			{
				firstCluster = root[index + 26 + 0] | (root[index + 26 + 1] << 8) | (root[index + 20 + 0] << 16) | (root[index + 20 + 1] << 24);
				fileSize = root[index + 28 + 0] | (root[index + 28 + 1] << 8) | (root[index + 28 + 2] << 16) | (root[index + 28 + 3] << 24);
			}
			else
			{
				throw new Exception("not found boot.bin");
			}

			short[] fat = new short[blocksPerFat * 256];
			for (int i = 0; i < blocksPerFat; i++)
			{
				byte[] fattemp = sd.ReadSector(fatStartBlock + i);
				for (int j = 0; j < 256; j++)
				{
					fat[i * 256 + j] = (short)(fattemp[j * 2] + (fattemp[j * 2 + 1] << 8));
				}
			}

			int blocks = 0;
			int start = firstCluster;
			while (true)
			{
				int oldStart = start;
				start = fat[start];
				blocks++;
				if (start == -1)
				{
					break;
				}
				if (start != oldStart + 1)
				{
					throw new Exception("not continue block");
				}

			}

			int sectorsPerCluster = fbs[3 + 8 + 2];

			int blockOfCluster = 0;
			int firstBlock = dataStartBlock + (firstCluster - 2) * sectorsPerCluster + blockOfCluster;

			byte[] data = sd.ReadSector(firstBlock);


			int bootrec = 3 + 8 + 41 + 12 + 7 + 11 + 8;
			fbs[bootrec + 0] = 0x12;
			fbs[bootrec + 1] = 0x34;
			fbs[bootrec + 2] = 0x56;
			fbs[bootrec + 3] = 0x78;

			fbs[bootrec + 4] = (byte)((firstBlock >> 0) & 0xFF);
			fbs[bootrec + 5] = (byte)((firstBlock >> 8) & 0xFF);
			fbs[bootrec + 6] = (byte)((firstBlock >> 16) & 0xFF);
			fbs[bootrec + 7] = (byte)((firstBlock >> 24) & 0xFF);

			fbs[bootrec + 8] = (byte)((blocks >> 0) & 0xFF);
			fbs[bootrec + 9] = (byte)((blocks >> 8) & 0xFF);
			fbs[bootrec + 10] = (byte)((blocks >> 16) & 0xFF);
			fbs[bootrec + 11] = (byte)((blocks >> 24) & 0xFF);

			sd.WriteSector(fbs, 0);
			MessageBox.Show("ok");
			sd.Close();
		}

		private void button11_Click(object sender, EventArgs e)
		{
			clearBuff();

			loadSym();

            portWriteNew((byte)(0x01), 1);//halt_uart

            uint baseAddr = 0x00000000;

			loadprog("out.hex", baseAddr);

			//      end else if (command == 8'h02) begin debug_reset_n<=data[0]; command_done<=1;

            //debug mode
            setmem(0x54000000 + 4, 1);//cs
            setmem(0x54000000 + 0, 0x80 | (0x20 << 1) | 0);//write ds1302 ram[0]
            setmem(0x54000000 + 0, 1);
            setmem(0x54000000 + 4, 0);//cs


            portWriteNew((byte)(0x02), 0);//reset
            portWriteNew((byte)(0x02), 1);

			if (!checkBox1.Checked)
			{
                portWriteNew((byte)(0x01), 0);//release halt_uart
			}
		}
		public void loadprog(string filename, uint baseAddr)
		{
			FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read);
			StreamReader sr = new StreamReader(fs);
			String s = sr.ReadToEnd();
			sr.Close();
			fs.Close();

			int index = 0;
			uint[] data = new uint[s.Split('\n').Length];
			foreach (var item in s.Split('\n'))
			{
				if (item.Length == ":040016001005003a97".Length + 1)
				{
					//:04001600 1005003a 97
					String str = item.Substring(9, 8);
					data[index] = Convert.ToUInt32(str, 16);
					index++;
				}
			}
			for (uint i = 0; i < data.Length; i += 256)//data.Length
			{
				bool error = false;
				string sretry = "";
				for (int retry = 0; retry < 5; retry++)
				{
					error = false;
					//:04001600 1005003a 97
                    for (uint j = i; j < i + 256 && j < data.Length; j++)
					{
						bool result = setmem((uint)(baseAddr + j * 4), data[j], true);
						if (!result)
						{
							error = true;
							break;
						}
					}
                    FlushCache(baseAddr + i * 4);
                    portWriteNew(0x69, 1);//nocache
                    for (uint j = i; j < i + 256 && j < data.Length; j++)
					{
						uint b = getmem(((uint)(baseAddr + j * 4)), null);
						if (data[j] != b)
						{
							error = true;
							break;
						}
					}
                    portWriteNew(0x69, 0);//nocache
					if (!error)
					{
						break;
					}
					else
					{
                        clearBuff();
						sretry = "retry";
					}
				}

				if (error)
				{
					MessageBox.Show("err");
					break;
				}
				this.Text = (i * 4).ToString() + sretry;
				Application.DoEvents();

			}

            setmem((uint)(CACHE_CTL), 0x40000000);
            setmem(CACHE_CTL, 0);


		}

        uint VGA = 0x4C200000;
        uint VGA_MODE = 0x0000;
        uint VGA_BLOCK = 0x0800;
        uint VGA_BASE = 0x1000;
        uint VGA_CURSOR_DATA = 0x1800;
        uint VGA_CURSOR_X = 0x2000;
        uint VGA_CURSOR_Y = 0x2800;
        private void trackBar1_Scroll(object sender, EventArgs e)
        {
            setmem(VGA + VGA_BASE, (uint)(trackBar1.Value));
        }

		private void checkBox2_CheckedChanged(object sender, EventArgs e)
		{
		}

		private void checkBox3_CheckedChanged(object sender, EventArgs e)
		{
			if (checkBox3.Checked)
			{
				setmem(0x02040000, 0);
			}
			else
			{
				setmem(0x02040000, 2);
			}

		}


		private void button14_Click(object sender, EventArgs e)
		{
            portWriteNew((byte)(0x15), (byte)0x00);
            uint temp = readFromPort();
            this.Text = temp+"";
            //portWriteNew(0x69, 1);//nocache
            //writeByteEnable(0xF);
            //setmem((uint)0x00000000, (uint)0x12345678);
            //setmem((uint)0x00000004, (uint)0x44444444);
            //setmem((uint)0x00000008, (uint)0x88888888);
            //setmem((uint)0x0000000C, (uint)0xCCCCCCCC);
            //setmem((uint)0x00000010, (uint)0x00000000);
            //setmem((uint)0x00000014, (uint)0x11111111);
            //setmem((uint)0x00000018, (uint)0x22222222);
            //checkBox8_CheckedChanged(null, null);//nocache
		}


		private void checkBox4_CheckedChanged(object sender, EventArgs e)
		{

		}

        private void button16_Click_1(object sender, EventArgs e)
        {
            Form3 form3 = new Form3();
            form3.mainForm = this;
            form3.Show();
            stop = true;
        }

        private void checkBox8_CheckedChanged(object sender, EventArgs e)
        {
            if (checkBox8.Checked)
            {
                portWriteNew(0x69, 1);//nocache
            }
            else
            {
                portWriteNew(0x69, 0);//nocache
            }
        }


	}
}
